package org.example.everyday;

import java.util.ArrayDeque;
import java.util.Deque;

public class Lc591 {
    public static void main(String[] args) {
        Lc591 lc591 = new Lc591();
        String code = "<DIV>>>  ![cdata[]] <![CDATA[<div>]>]]>]]>>]</DIV>";
        boolean res = lc591.isValid(code);
        System.out.println(res);
    }

    /**
     * 方法描述: 验证是否合法
     *
     * @param code .
     * @return boolean
     * @author 安路路
     * @date 2022/5/3 0003  21:57
     */
    public boolean isValid(String code) {
        //获取要验证的字符串的长度
        int n = code.length();
        //声明一个栈的数据结构
        Deque<String> tags = new ArrayDeque<String>();
        int i = 0;
        while (i < n){
            if(code.charAt(i) == '<'){
                //如果 < 符号出现在最后一位，那肯定是不合法的，直接返回false
                if(i == n - 1){
                    return false;
                }
                //如果 '/' 后面没有找到 > 结束字符，则不合法，返回FALSE
                if(code.charAt(i + 1) == '/'){
                    int j = code.indexOf('>',i);
                    if(j < 0){
                        return false;
                    }
                    //获取标签的名称，比如</DIV>
                    String tagName = code.substring(i + 2,j);
                    //如果标签的栈中为空 || 栈中取出得元素标签 ！= 当前取出的标签名称， 以上情况则返回false,不合法
                    if(tags.isEmpty() || !tags.peek().equals(tagName)){
                        return false;
                    }
                    //以上都不满足的话，则说明当前标签合法
                    tags.pop();

                    i = j + 1;
                    //如果标签栈中空了 && 没有遍历到最后一个字符，则说明也不是一个合法的字符串，返回FALSE
                    if(tags.isEmpty() && i != n){
                        return false;
                    }
                } else if(code.charAt(i + 1) == '!'){
                    if(tags.isEmpty()){
                        return false;
                    }
                    //<![CDATA[  这个是cdata标签的开始部分，如果大于字符长度，则说明不合法
                    if(i + 9 > n){
                        return false;
                    }
                    //获取cdata标签的前半部分：![CDATA[
                    String cdata = code.substring(i + 2,i + 9);
                    if(!"[CDATA[".equals(cdata)){
                        return false;
                    }
                    //获取cdata的结束标签部分，如果没有找到，则返回FALSE
                    int j = code.indexOf("]]>",i);
                    if(j < 0){
                        return false;
                    }
                    //如果找到了，则 i指针 往后移动3位
                    i = j + 3;
                } else{
                    int j = code.indexOf('>',i);
                    if(j < 0){
                        return false;
                    }
                    //获取标签的名称，如果长度小于1或者长度大于9，都说明字符不合法
                    String tagname = code.substring(i + 1, j);
                    if(tagname.length() < 1 || tagname.length() > 9){
                        return false;
                    }
                    //遍历标签的每个字符，看看是不是大写字符，如果不是，则说明不合法
                    for(int k = 0; k < tagname.length(); k++){
                        if(!Character.isUpperCase(tagname.charAt(k))){
                            return false;
                        }
                    }
                    //把当前标签放入栈中
                    tags.push(tagname);
                    i = j + 1;
                }
            } else {
                //如果还没有遍历完，栈中的标签就为空了，则说明不合法，肯定不对啊
                if(tags.isEmpty()){
                    return false;
                }
                i++;
            }
        }

        return tags.isEmpty();
    }
}
